#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
description: please input using description
author: justbk
date: 2023/10/17
modify_records:
    - 2023/10/17 justbk create this file
"""
from .Field import Field
from .DbOperator import DbOperator

class ModeMetaClass(type):
    def __new__(cls, name, bases, attrs):
        if name == 'Model':
            return type.__new__(cls, name, bases, attrs)
        mappings = dict()
        print('Found class :%s' % name)
        for k, v in attrs.items():
            if isinstance(v, Field):
                print('Found mapping:%s ==> %s' % (k, v))
                mappings[v.name] = v
        if k in mappings.keys():
            attrs.pop(k)
        attrs["__table__"] = name
        attrs["__mappings__"] = mappings

        attrs["__create__"] = 'create table if not exists %s (%s)' %(name, ", ".join(map(lambda v: "%s %s" %(v.name, v.column_type),
                                                                     mappings.values())))
        attrs["__truncate__"] = 'truncate %s'%(name)
        attrs["__drop__"] = 'drop table if exists %s'%(name)
        attrs["__select__"] = 'select %s from %s'%(",".join(mappings.keys()), name)
        len_size = len(mappings.keys())
        result = ",".join(list(map(lambda x: '?', range(len_size))))
        print(result)
        attrs["__insert__"] = 'insert into %s (%s) values (%s)'%(name,
                                                                ",".join(mappings.keys()),
                                                                result)
        return type.__new__(cls, name, bases, attrs)

class Model(metaclass=ModeMetaClass):
    def __init__(self, **kwargs):
        _setattr = setattr
        if kwargs:
            for k, v in kwargs.items():
                _setattr(self, k, v)
        super(Model, self).__init__()

    def create(self, db: DbOperator):
        self._execute_sql(db, self.__create__)

    def truncate(self, db:DbOperator):
        self._execute_sql(db, self.__truncate__)

    def drop(self, db:DbOperator):
        self._execute_sql(db, self.__drop__)

    def _execute_sql(self, db:DbOperator, sql):
        print("execute sql:%s" %(sql))
        db.execute(sql)


    def save(self, db_operator:DbOperator):
        args = self.to_sql_data()
        print('insert sql:%s' %(self.__insert__))
        print('args:%s' %(str(args)))
        db_operator.execute(self.__insert__, args)

    def get_insert_sql(self):
        return self.__insert__

    def to_sql_data(self):
        args = []
        for k, v in self.__mappings__.items():
            args.append(getattr(self, k, None))
        return tuple(args)

    def query(self, db:DbOperator):
        condition, param = self._default_query_condition()
        return self.query_condition(db, condition, param)

    def query_condition(self, db:DbOperator, condition, param):
        sql = self.__select__ + " " + condition
        print("query sql:%s" % sql)
        rows = db.query(sql, param)
        return self._parse_list(rows)


    def _default_query_condition(self):
        args = []
        param = []
        for k, v in self.__mappings__.items():
            val = getattr(self, k, None)
            if val is not None:
                args.append(k)
                param.append(val)

        if len(args) == 0:
            return "", []
        return " where %s" % (" and ".join(map(lambda key: '%s = ?' % key, args))), param

    def _parse_list(self, rows):
        if rows is None:
            return []
        return list(map(lambda row: self._parse(row), rows))

    def _parse(self, row):
        kwargs = {}
        i = 0
        for k, v in self.__mappings__.items():
            kwargs[v.name] = row[i]
            i += 1
        return self.__class__(**kwargs)
        # for k, v in self.__mappings__.items():
        #     row


